package com.fezs.job.aop;

import com.fezs.common.context.BaseContextHandler;
import com.fezs.common.exception.ArgumentException;
import com.fezs.common.exception.BusinessException;
import com.fezs.common.utils.TraceIdUtils;
import com.fezs.message.entity.MsgEntity;
import com.fezs.message.template.MessageTemplate;
import com.xxl.job.core.context.XxlJobContext;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.lang.reflect.Method;

/**
 * @author zhukai
 * @since 2022/8/18
 */
@Slf4j
@Aspect
public class XxlJobAop {

    @Value("${spring.application.name}")
    private String appName;

    @Value("${spring.profiles.active}")
    private String profile;

    @Autowired(required = false)
    private MessageTemplate messageTemplate;

    @Around("@annotation(jobAnno)")
    public Object around(ProceedingJoinPoint joinPoint, XxlJob jobAnno) throws Throwable {
        BaseContextHandler.setTraceId(TraceIdUtils.putTraceId());
        long start = System.currentTimeMillis();
        log.info("定时任务[{}]执行开始, 参数:{}", jobAnno.value(), XxlJobContext.getXxlJobContext().getJobParam());
        try {
            return joinPoint.proceed();
        } catch (Throwable t) {
            log.error("定时任务[" + jobAnno.value() + "]执行异常", t);
            this.sendErrorMessage(joinPoint, jobAnno, t);
            throw t;
        } finally {
            log.info("定时任务[{}]执行结束, 耗时:{}ms", jobAnno.value(), System.currentTimeMillis() - start);
            TraceIdUtils.clear();
            BaseContextHandler.remove();
        }
    }

    private void sendErrorMessage(ProceedingJoinPoint joinPoint, XxlJob jobAnno, Throwable t) {
        if (messageTemplate == null) {
            return;
        }
        if (t instanceof ArgumentException || t instanceof BusinessException) {
            return;
        }
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();

        String content = MsgEntity.getJobMarkdownMsg(appName, profile, method.getDeclaringClass().getName(), method.getName(), t);
        MsgEntity msgEntity = MsgEntity.buildMarkdownMsg(content);
        messageTemplate.send(msgEntity);
    }

}
